package org.jing.ext.pdf.itextpdf;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import org.jing.core.lang.JingException;
import org.jing.core.logger.JingLogger;
import org.jing.core.util.GenericUtil;
import org.jing.ext.example.Example4PdfTemplate;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Description: PDF模板. <br>
 *
 * @author bks <br>
 * @see Example4PdfTemplate#Example4PdfTemplate() 用例<br>
 * @since 2020-11-04 <br>
 */
@SuppressWarnings({ "unused", "RedundantThrows" })
public class PdfTemplate implements Closeable {
    private static final JingLogger LOGGER = JingLogger.getLogger(PdfTemplate.class);

    private volatile PdfReader reader;

    private BaseFont baseFontStyle = null;

    private BaseColor baseFontColor = null;

    private float baseFontSize = -1;

    /**
     * Description: 根据模板文件实例化一个Pdf模板对象出来. <br>
     * @param templateFilePath 模板文件路径 <br>
     */
    public PdfTemplate(String templateFilePath) {
        try {
            reader = new PdfReader(templateFilePath);
            LOGGER.debug("Build Pdf template with file: {}", templateFilePath);
        }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new JingException(t);
        }
    }

    @Override protected void finalize() throws Throwable {
        close();
        super.finalize();
    }

    /**
     * Description: 设置全局字体样式. <br>
     * @param fontString <br>
     */
    public void setBaseFont(String fontString) {
        this.baseFontStyle = FontFactory.getFont(fontString, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED,28f, Font.NORMAL, BaseColor.BLACK).getBaseFont();
        LOGGER.debug("Set global font style: {}", fontString);
    }

    /**
     * Description: 设置全局字体样式. <br>
     * @param baseFont <br>
     */
    public void setBaseFont(BaseFont baseFont) {
        this.baseFontStyle = baseFont;
        LOGGER.debug("Set global font style: {}", baseFont.getPostscriptFontName());
    }

    /**
     * Description: 设置全局字体颜色. <br>
     * @param red <br>
     * @param green <br>
     * @param blue <br>
     */
    public void setBaseColor(int red, int green, int blue) {
        baseFontColor = new BaseColor(red, green, blue);
        LOGGER.debug("Set global font color: [{}, {}, {}]", red, green, blue);
    }

    /**
     * Description: 设置全局字体大小. <br>
     * @param fontSize <br>
     */
    public void setBaseFontSize(float fontSize) {
        baseFontSize = fontSize;
        LOGGER.debug("Set global font size: {}", fontSize);
    }

    /**
     * Description: 输出到指定文件里. <br>
     *     采用了申请资源式写法, 不用担心输出流是否会关闭的问题. <br>
     * @param dataRowList 数据列表 <br>
     * @param outputFile 输出文件 <br>
     */
    public void mapDataAndWrite(List<DataRow> dataRowList, File outputFile) {
        try {
            LOGGER.debug("Generate PDF...");
            LOGGER.debug("data: {}", dataRowList);
            LOGGER.debug("output: {}", outputFile.getAbsolutePath());
            int count = GenericUtil.count(dataRowList);
            if (0 != count) {
                try (ByteArrayOutputStream writer = new ByteArrayOutputStream()) {
                    PdfStamper stamper = new PdfStamper(reader, writer);
                    AcroFields fields = stamper.getAcroFields();
                    fields.setGenerateAppearances(true);
                    if (null != baseFontStyle) {
                        // 一次性全部设置字体样式
                        ArrayList<BaseFont> fontList = new ArrayList<>();
                        fontList.add(baseFontStyle);
                        fields.setSubstitutionFonts(fontList);
                    }
                    DataRow dataRow;
                    for (int i$ = 0; i$ < count; i$++) {
                        dataRow = dataRowList.get(i$);
                        if (null != dataRow.getFontStyle()) {
                            fields.setFieldProperty(dataRow.getKey(), "textfont", dataRow.getFontStyle(), null);
                        }
                        if (null != dataRow.getFontColor()) {
                            fields.setFieldProperty(dataRow.getKey(), "textcolor", dataRow.getFontColor(), null);
                        }
                        else if (null != baseFontColor) {
                            fields.setFieldProperty(dataRow.getKey(), "textcolor", baseFontColor, null);
                        }
                        if (-1 < dataRow.getFontSize()) {
                            fields.setFieldProperty(dataRow.getKey(), "textsize", dataRow.getFontSize(), null);
                        }
                        else if (-1 < baseFontSize) {
                            fields.setFieldProperty(dataRow.getKey(), "textsize", baseFontSize, null);
                        }
                        fields.setField(dataRow.getKey(), dataRow.getValue());
                    }
                    stamper.setFormFlattening(true);
                    stamper.close();
                    try (OutputStream fos = new FileOutputStream(outputFile)) {
                        fos.write(writer.toByteArray());
                        fos.flush();
                    }
                }
            }
        }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new JingException(t);
        }
    }

    @Override
    public void close() throws IOException {
        if (null != reader) {
            reader.close();
            reader = null;
        }
    }
}
